import bpy, os
import numpy as np
import copy
from math import radians


# from bpy_extras.object_utils import world_to_camera_view
# x_res = bpy.context.scene.render.resolution_x
# y_res = bpy.context.scene.render.resolution_y
# for i, v in enumerate(bpy.context.object.data.vertices):
#     cam_coord_vec = world_to_camera_view(bpy.context.scene, bpy.data.objects['Camera'], bpy.context.object.matrix_world @ v.co)
#     print(f"vertex # {i} has camera coordinates vector: {cam_coord_vec}")
#     x_pixel = x_res * cam_coord_vec.x
#     y_pixel = y_res * cam_coord_vec.y
#     print(f"in pixels (unrounded): {x_pixel, y_pixel}")
#     if 0.0 <= x_pixel <= x_res and 0.0 <= y_pixel <= y_res:
#         print(f"in pixels (truncated): {int(x_pixel), int(y_pixel)}")
#         print(f"in pixels (rounded): {round(x_pixel), round(y_pixel)}")
#     else:
#         print(f"Vertex lies outside of camera view.")

class Cam:
    def __init__(self):
        self.ex = self.extrinsic()
        self.K, self.W, self.H = self.intrinsic()
        self.loc, self.eu = self.cam_origin()

    def render(self, path):
        # BLENDER_EEVEE_NEXT', 'BLENDER_WORKBENCH', 'CYCLES'
        # bpy.context.scene.render.engine = 'CYCLES'
        # bpy.context.scene.render.engine = 'BLENDER_EEVEE_NEXT'
        bpy.context.scene.render.engine = 'BLENDER_WORKBENCH'
        bpy.context.scene.render.filepath = path
        # 执行渲染操作
        bpy.ops.render.render(write_still=True)

    def intrinsic(self):
        scene = bpy.context.scene
        render = scene.render
        camera = bpy.data.objects["Camera"]
        # 获取相机的传感器尺寸（以毫米为单位）
        sensor_width = camera.data.sensor_width  # 传感器宽度
        sensor_height = camera.data.sensor_height  # 传感器高度
        # 获取相机的焦距（以毫米为单位）
        focal_length = camera.data.lens
        # 获取图像分辨率（以像素为单位）
        resolution_x = render.resolution_x
        resolution_y = render.resolution_y

        # 计算内参矩阵 K
        f_x = focal_length * resolution_x / sensor_width
        f_y = focal_length * resolution_y / sensor_height

        c_x = resolution_x / 2  # 假设主点在图像中心
        c_y = resolution_y / 2  # 假设主点在图像中心

        K = np.array([
            [f_x, 0, c_x],
            [0, f_y, c_y],
            [0, 0, 1]
        ])
        return K, resolution_x, resolution_y

    def wordloc2camloc(self, loc):
        loc=copy.deepcopy(loc)
        scene = bpy.context.scene
        cam = bpy.data.objects["Camera"]
        cam_mat_iv = np.array(cam.matrix_world.normalized().inverted())
        loc.append(1)
        loc = np.array(loc)
        co_local = cam_mat_iv @ loc
        z = -co_local[2]
        camera = cam.data
        frame = [v for v in camera.view_frame(scene=scene)[:3]]
        if camera.type != 'ORTHO':
            if z == 0.0:
                return np.array([0.5, 0.5, 0.0])
            else:
                frame = [-(v / (v.z / z)) for v in frame]

        min_x, max_x = frame[2].x, frame[1].x
        min_y, max_y = frame[1].y, frame[0].y

        x = (co_local[0] - min_x) / (max_x - min_x)
        y = (co_local[1] - min_y) / (max_y - min_y)

        return np.array([x, y, z])

    def wordloc2uv(self, loc):
        camloc = self.wordloc2camloc(loc)
        scene = bpy.context.scene
        render_scale = scene.render.resolution_percentage / 100
        render_size = (
            int(scene.render.resolution_x * render_scale),
            int(scene.render.resolution_y * render_scale),
        )
        uv = (
            int(camloc[0] * render_size[0]),
            int((1 - camloc[1]) * render_size[1]),
        )
        return uv

    def extrinsic(self):
        camera = bpy.data.objects["Camera"]
        arr = camera.matrix_world
        arr = arr.inverted()
        arr = np.array(arr)
        return arr

    def cam_origin(self):
        camera = bpy.data.objects["Camera"]
        return copy.deepcopy(camera.location), copy.deepcopy(camera.rotation_euler)

    def move_cam(self):
        camera = bpy.data.objects["Camera"]
        print(camera.location, camera.rotation_euler)
        # camera.location = (10, 7, 8)
        # camera.rotation_euler = ([radians(a) for a in (56, 0.5, 127)])
        camera.location = (10, -5, 5)
        camera.rotation_euler = ([radians(a) for a in (64.5, 20, 51.6)])

    def move_cam_back(self):
        camera = bpy.data.objects["Camera"]
        camera.location = self.loc
        camera.rotation_euler = self.eu


if __name__ == '__main__':
    c = CreateScent()
    c.run()
